from playwright.sync_api import sync_playwright
from flask import Flask, request, Response, jsonify, send_from_directory
from flask_cors import CORS
import threading, socket, os, sys, subprocess, ini_op, time, duckdb, rpa_run, uuid, json

from databaseRequest import database


app = Flask(__name__, static_folder='static', template_folder='templates')
# 允许跨域传输数据
CORS(app)

# 注册 Blueprint
app.register_blueprint(database, url_prefix='/sql')

BASE_DIR = os.path.dirname(os.path.realpath(sys.argv[0]))
app_port, chrome_port, browser_select, browser_path = ini_op.getinivalue('basic_config', 'app_port', 'chrome_port', 'browser_select', 'browser_path')


# 处理 React 前端路由（所有其他路由返回 React 应用）
@app.route('/page', defaults={'path': ''})
@app.route('/page/<path:path>')
def serve_page_app(path):
    page_path = os.path.join(app.static_folder, 'page', 'static')
    if path != "" and os.path.exists(os.path.join(page_path, path)):
        return send_from_directory(page_path, path)
    else:
        return send_from_directory(page_path, 'index.html')
@app.route('/work', defaults={'path': ''})
@app.route('/work/<path:path>')
def serve_sql_app(path):
    sql_path = os.path.join(app.static_folder, 'work', 'static')
    if path != "" and os.path.exists(os.path.join(sql_path, path)):
        return send_from_directory(sql_path, path)
    else:
        print(sql_path)
        return send_from_directory(sql_path, 'index.html')
@app.route('/calc', defaults={'path': ''})
@app.route('/calc/<path:path>')
def serve_database(path):
    return send_from_directory(app.template_folder, 'calc.html')

#上传文件
@app.route('/rpa/file_upload/upload', methods=['POST'])
def upload_file():
    if 'file' not in request.files:
        return jsonify('未识别到文件'), 400
    file = request.files['file']
    if file.filename == '':
        return jsonify('未识别到文件'), 400
    # 获取文件扩展名
    file_extension = file.filename.rsplit('.', 1)[1].lower()
    uuid4 = uuid.uuid4()
    # 生成唯一的文件名
    unique_filename = f"{uuid4}.{file_extension}"
    savepath = ini_op.getinivalue('pdf_config', 'import_folder')[0]
    os.makedirs(savepath, exist_ok=True)
    filepath = os.path.join(savepath, unique_filename)
    file.save(filepath)
    conn = duckdb.connect('data.db')
    conn.execute("INSERT INTO t_import_files (id, uniqueName, realName, filepath, type) VALUES (?, ?, ?, ?, 'file')", (uuid4, unique_filename, file.filename, filepath))
    conn.close()
    return jsonify({"code":200, "fileId":uuid4}), 200

# 凭证上传配置
@app.route('/rpa/pdfDownload/config', methods=['GET', 'POST'])
def rpa_pzsc():
    data = ini_op.getjson('pdf_config')
    # 返回JSON响应
    data = json.dumps(data, ensure_ascii=False)
    return Response(data, content_type="application/json")

@app.route('/rpa/pdfDownload/run', methods=['POST'])
def pdfDownload_run():
    type = request.json.get('type')
    if type == 'excel':
        fileList = request.json.get('list')
        rpa_run.run('联合打印','excel', fileList)
        return jsonify({"code":200, "filePath":fileList}), 200
    elif type == 'config':
        data = request.json.get('data')
        print(data)
        ini_op.opinivalue('pdf_config', **data)
        uuid4 = uuid.uuid4()
        conn = duckdb.connect('data.db')
        conn.execute("""INSERT INTO t_import_files (id, uniqueName, realName, filepath, type) 
                     VALUES (?, ?, ?, ?, 'config')""", (uuid4, '', '凭证日期；'+data['start_date']+' - '+data['end_date']+'，凭证号：'+data['start_pz_no']+' - '+data['end_pz_no'], ''))
        conn.close()
        rpa_run.run('联合打印', 'config', str(uuid4))
        return jsonify({"code":200, "data":data}), 200
    else:
        return jsonify({"code":400, "msg":"未知Tab类型"}), 400
    
#历史上传列表
@app.route('/rpa/pdfDownload/runList', methods=['GET'])
def pdfDownload_runList():
    conn = duckdb.connect('data.db')
    pdf_folder = ini_op.getinivalue('pdf_config', 'pdf_folder')[0]
    pdf_folder = os.path.join(BASE_DIR, pdf_folder)
    rows = conn.execute(f"select *, concat('{pdf_folder}','\\',id) as path from t_import_files order by importDate desc").fetchdf()
    # 将日期列格式化为原始格式
    rows['importDate'] = rows['importDate'].dt.strftime('%Y-%m-%d %H:%M:%S')
    rows = rows.to_dict('records')
    conn.close()
    return jsonify({"code":200, "data":rows}), 200
#删除历史文件
# @app.route('/rpa/pdfDownload/runList/delete', methods=['POST'])
# def pdfDownload_runList_delete():
#     id = request.json.get('id')
#     conn = duckdb.connect('data.db')
#     conn.execute("delete from t_import_files where id = ?", [id])
#     conn.execute("delete from t_pdf_download where parentId = ?", [id])
#     conn.close()
#     return jsonify({"code":200, "msg":"删除成功"}), 200
#历史PDF列表
@app.route('/rpa/pdf/list', methods=['GET'])
def pdf_list():
    conn = duckdb.connect('data.db')
    rows = conn.execute("select * from t_pdf_sort order by year desc, month desc, pzh desc").fetchdf()
    # 将日期列格式化为原始格式
    rows['updateTime'] = rows['updateTime'].dt.strftime('%Y-%m-%d %H:%M:%S')
    rows = rows.to_dict('records')
    conn.close()
    return jsonify({"code":200, "data":rows}), 200
#上传文件下载
@app.route('/rpa/pdfDownload/fileDownload', methods=['GET'])
def pdfDownload_download():
    id = request.args.get('id')
    conn = duckdb.connect('data.db')
    data = conn.execute("select filepath, realName from t_import_files where id = ?", [id]).fetchall()[0]
    conn.close()
    directory = os.path.dirname(data[0])
    filename = os.path.basename(data[0])
    return send_from_directory(directory, filename, as_attachment=True, download_name=data[1])
#模板下载
@app.route('/rpa/mode/fileDownload', methods=['GET'])
def mode_download():
    filename = request.args.get('name')
    directory = 'importMode'
    return send_from_directory(directory, filename, as_attachment=True, download_name=filename)
#pdf预览
@app.route('/rpa/pdf/view', methods=['GET'])
def pdf_view():
    id = request.args.get('id')
    conn = duckdb.connect('data.db')
    data = conn.execute("""
        select filepath, fileName from t_pdf_download where id = ?
        union all
        select filepath, fileName from t_pdf_sort where id = ?
    """, [id, id]).fetchall()[0]
    conn.close()
    directory = os.path.dirname(data[0])
    filename = os.path.basename(data[0])
    return send_from_directory(directory, filename, as_attachment=False, download_name=data[1])
@app.route('/rpa/pdf/download', methods=['GET'])
def pdf_download():
    id = request.args.get('id')
    with sync_playwright() as playwright:
        browser = playwright.chromium.connect_over_cdp('http://localhost:'+chrome_port)
        context = browser.contexts[0]
        page = context.new_page()
        page.goto('http://127.0.0.1:'+app_port+'/rpa/pdf/view?id='+id)
        browser.close()
    return 'ok'

@app.route('/rpa/pdfDownload/dataList', methods=['GET'])
def pdfDownload_dataList():
    id = request.args.get('id')
    conn = duckdb.connect('data.db')
    rows = conn.execute("""
        select concat(id,'') as id, dlTime as updateTime, fileName, filepath, '-' as year, '-' as month, '-' as pzh from t_pdf_download where parentId = ? and fileName = '联合打印.pdf'
        union all
        --select id, updateTime, fileName, filepath, year, month, pzh from t_pdf_sort where fileName in (select fileName from t_pdf_download where parentId = ?)
        select concat(t1.id,';',t2.id) as id, t1.updateTime, t1.fileName, t1.filepath, t1.year, t1.month, t1.pzh from t_pdf_sort t1 left join t_pdf_download t2 on t1.fileName = t2.fileName where t2.parentId = ?
    """, [id, id]).fetchdf()
    # 将日期列格式化为原始格式
    rows['updateTime'] = rows['updateTime'].dt.strftime('%Y-%m-%d %H:%M:%S')
    rows = rows.to_dict('records')
    conn.close()
    return jsonify({"code":200, "data":rows}), 200

@app.route('/rpa/sysConfig/get', methods=['GET'])
def sysConfig_get():
    basic_config = ini_op.getjson('basic_config')
    pdf_config = ini_op.getjson('pdf_config')
    request_config = ini_op.getjson('request_config')
    data = {"basic_config":basic_config, "pdf_config":pdf_config,"request_config":request_config}
    return jsonify({"code":200, "data":data}), 200

@app.route('/rpa/sysConfig/update', methods=['POST'])
def sysConfig_update():
    data = request.json
    ini_op.opinivalue('basic_config', **data['basic_config'])
    ini_op.opinivalue('pdf_config', **data['pdf_config'])
    ini_op.opinivalue('request_config', **data['request_config'])
    return jsonify({"code":200, "data":"success"}), 200

@app.route('/rpa/openFolder', methods=['POST'])
def rpa_openFolder():
    path = request.args.get('path')
    print(path)
    os.startfile(path)
    return jsonify({"message":"success"}), 200

# 浏览器启动函数
#若已启动则取消再次运行
def check_port_in_use(port):
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
        return s.connect_ex(('127.0.0.1', port)) != 0
def open_browser1(app_port, chrome_port, browser_path):
    browser_path = os.path.join(BASE_DIR, browser_path)
    url = 'http://127.0.0.1:'+app_port+'/page'
    command = [
        browser_path,
        f'--remote-debugging-port={chrome_port}',
        '--start-maximized',
        url,
    ]
    browser_process = subprocess.Popen(command)
    # 监控浏览器进程
    while True:
        # 检查进程是否仍在运行
        retcode = browser_process.poll()
        if retcode is not None:
            # 如果进程已结束，调用 os._exit(0) 终止程序
            os._exit(0)
        time.sleep(1)

def open_browser2(app_port, chrome_port):
    with sync_playwright() as p:
        # 设置启动参数
        args = [
            '--start-maximized',
            f'--remote-debugging-port={chrome_port}'
        ]
        browser_path = os.path.join(BASE_DIR, 'Browser Data')
        os.makedirs(browser_path, exist_ok=True)
        browser = p.chromium.launch_persistent_context(browser_path, headless=False, ignore_https_errors=True, accept_downloads=True, slow_mo=50, no_viewport=True, args=args)
        try:
            page = browser.pages[0]
        except Exception:
            page = browser.new_page()
        try:
            page.goto('http://127.0.0.1:'+app_port+'/page')
        except Exception:
            pass
        try:
            page.wait_for_selector('#cjdshsjkskfsk', timeout=300000000)
        except Exception:
            browser.close()
        finally:
            os._exit(0)


if __name__ == '__main__':
    # 仅在主进程中启动浏览器线程
    if check_port_in_use(int(app_port)):
        if browser_select == '1':
            browser_thread = threading.Thread(target=open_browser1, args=[app_port, chrome_port, browser_path])
        else:
            browser_thread = threading.Thread(target=open_browser2, args=[app_port, chrome_port])
        browser_thread.start()
        app.run(host='0.0.0.0',port=app_port)